import { Element, PaintContext } from './element'
import { Div } from './div'
import { styledDiv } from './styled'
import { ReactiveComponent } from './signals'
import { App } from './app'
import { EntityId } from './entity_map'

/**
 * 内部响应式组件实现
 */
class InternalReactiveComponent extends ReactiveComponent {
  // 继承自ReactiveComponent的所有功能
}

/**
 * 组件属性接口
 */
export interface ComponentProps {
  [key: string]: any
  children?: Element | Element[] | string
}

/**
 * 组件生命周期接口
 */
export interface ComponentLifecycle {


  /**
   * 组件卸载前调用
   */
  onUnmount?(): void
}

/**
 * 上下文接口
 */
export interface Context<T> {
  /**
   * 通知实体变更
   */
  notify(entityId: EntityId): void
  
  /**
   * 获取应用实例
   */
  getApp(): App
  
  /**
   * 获取当前实体
   */
  getEntity(): T
  
  /**
   * 获取弱引用实体
   */
  getWeakEntity(): T
}

/**
 * 组件接口
 */
export interface Component extends Element, ComponentLifecycle {
  props: ComponentProps
  render(): HTMLElement
}

/**
 * 上下文实现
 */
export class ContextImpl<T> implements Context<T> {
  private entity: T
  private app: App

  constructor(entity: T, app: App) {
    this.entity = entity
    this.app = app
  }

  notify(entityId: EntityId): void {
    this.app.notify(entityId)
  }

  getApp(): App {
    return this.app
  }

  getEntity(): T {
    return this.entity
  }

  getWeakEntity(): T {
    return this.entity
  }
}

/**
 * 基础组件类，集成了signals支持
 */
export abstract class BaseComponent extends Div implements Component {
  props: ComponentProps
  private mounted: boolean = false
  private prevProps: ComponentProps = {}
  private reactiveComponent: InternalReactiveComponent
  private context: Context<this> | null = null

  constructor(props: ComponentProps = {}) {
    super()
    this.props = props
    this.prevProps = { ...props }
    this.reactiveComponent = new InternalReactiveComponent()
  }

  /**
   * 更新组件属性
   */
  updateProps(props: ComponentProps): void {
    this.prevProps = { ...this.props }
    this.props = { ...this.props, ...props }
    
    if (this.mounted && this.onUpdate) {
      this.onUpdate(this.prevProps)
    }
    
    this.requestLayout({ needsLayout: true })
  }

  /**
   * 组件挂载后调用
   */
  onMount?(): void

  /**
   * 组件更新前调用
   */
  onUpdate?(prevProps: ComponentProps): void

  /**
   * 组件卸载前调用
   */
  onUnmount?(): void

  /**
   * 绘制组件
   */
  paint(context: PaintContext): HTMLElement {
    // 先调用父类的paint方法，确保绘制到Scene
    super.paint(context)
    
    // 然后调用render方法获取DOM元素
    const element = this.render()
    
    // 如果是第一次绘制，调用onMount
    if (!this.mounted && this.onMount) {
      this.mounted = true
      this.reactiveComponent.onMount()
      setTimeout(() => {
        this.onMount?.()
      }, 0)
    }
    
    return element
  }

  /**
   * 清理组件资源
   */
  cleanup(): void {
    if (this.onUnmount) {
      this.onUnmount()
    }
    this.reactiveComponent.onUnmount()
  }

  /**
   * 创建一个与组件生命周期绑定的响应式副作用
   * @param fn 副作用函数
   */
  protected createReactiveEffect(fn: () => void): void {
    this.reactiveComponent.createReactiveEffect(fn)
  }

  /**
   * 获取上下文实例
   */
  protected getContext(): Context<this> {
    if (!this.context) {
      // 从全局获取应用实例
      const app = (window as any)['gpuiApp'] || { notify: () => {} }
      this.context = new ContextImpl(this, app)
    }
    return this.context
  }

  /**
   * 通知实体变更
   */
  protected notify(entityId: EntityId): void {
    this.getContext().notify(entityId)
  }

  /**
   * 抽象渲染方法，由子类实现
   */
  abstract render(): HTMLElement
}

/**
 * 函数式组件类型
 */
export type FunctionalComponent<P extends ComponentProps = ComponentProps, R extends Element = Element> = (
  props: P
) => R

/**
 * 创建函数式组件
 */
export function createComponent<P extends ComponentProps, R extends Element = Element>(
  fn: FunctionalComponent<P, R>
): (props: P) => R {
  return (props: P) => {
    return fn(props)
  }
}

/**
 * 渲染子元素
 */
export function renderChildren(children: any, parent: Element): void {
  if (!children) return
  
  if (Array.isArray(children)) {
    children.forEach(child => {
      renderChild(child, parent)
    })
  } else {
    renderChild(children, parent)
  }
}

/**
 * 渲染单个子元素
 */
function renderChild(child: any, parent: Element): void {
  if (typeof child === 'string') {
    const textElement = styledDiv().setText(child)
    if ('addChild' in parent) {
      (parent as any).addChild(textElement)
    }
  } else if (child && typeof child === 'object' && 'render' in child) {
    if ('addChild' in parent) {
      (parent as any).addChild(child)
    }
  }
}